package com.example.docmanagement.service;

import com.example.docmanagement.dto.request.*;
import com.example.docmanagement.dto.response.PageResponse;
import com.example.docmanagement.dto.response.UserResponse;
import com.example.docmanagement.entity.Role;
import com.example.docmanagement.entity.User;
import com.example.docmanagement.entity.UserPermission;
import com.example.docmanagement.exception.DuplicateResourceException;
import com.example.docmanagement.exception.ResourceNotFoundException;
import com.example.docmanagement.repository.RoleRepository;
import com.example.docmanagement.repository.UserPermissionRepository;
import com.example.docmanagement.repository.UserRepository;
import jakarta.persistence.criteria.Predicate;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 管理后台 - 用户管理服务
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class UserAdminService {

    private static final Set<String> ALLOWED_STATUS = Set.of("active", "inactive", "banned");

    private final UserRepository userRepository;
    private final RoleRepository roleRepository;
    private final UserPermissionRepository userPermissionRepository;
    private final PasswordEncoder passwordEncoder;

    /**
     * 分页查询用户
     */
    @Transactional(readOnly = true)
    public PageResponse<UserResponse> searchUsers(UserQueryRequest request) {
        Pageable pageable = buildPageable(request.getPage(), request.getPageSize(), request.getSortBy(), request.getSortOrder());
        Specification<User> specification = buildSpecification(request);
        Page<User> page = userRepository.findAll(specification, pageable);
        List<User> users = page.getContent();

        Map<UUID, List<Long>> extraPermissionMap = buildExtraPermissionMap(users);
        Map<Long, Role> roleMap = buildRoleMap(users);

        List<UserResponse> data = users.stream()
                .map(user -> toResponse(user, extraPermissionMap, roleMap))
                .collect(Collectors.toList());

        return PageResponse.<UserResponse>builder()
                .data(data)
                .page(request.getPage())
                .pageSize(request.getPageSize())
                .total(page.getTotalElements())
                .totalPages(page.getTotalPages())
                .hasNext(page.hasNext())
                .hasPrevious(page.hasPrevious())
                .build();
    }

    /**
     * 获取用户详情
     */
    @Transactional(readOnly = true)
    public UserResponse getUser(UUID id) {
        User user = findActiveUser(id);
        Map<UUID, List<Long>> extraPermissionMap = buildExtraPermissionMap(Collections.singletonList(user));
        Map<Long, Role> roleMap = buildRoleMap(Collections.singletonList(user));
        return toResponse(user, extraPermissionMap, roleMap);
    }

    /**
     * 创建用户
     */
    @Transactional
    public UserResponse createUser(UserCreateRequest request) {
        validateStatus(request.getStatus());

        if (userRepository.existsByEmail(request.getEmail())) {
            throw new DuplicateResourceException("邮箱已存在", request.getEmail());
        }
        if (userRepository.existsByUsername(request.getUsername())) {
            throw new DuplicateResourceException("用户名已存在", request.getUsername());
        }

        Role role = roleRepository.findById(request.getRoleId())
                .orElseThrow(() -> new ResourceNotFoundException("角色不存在"));

        User user = new User();
        user.setEmail(request.getEmail().toLowerCase(Locale.ROOT));
        user.setUsername(request.getUsername());
        user.setEncryptedPassword(passwordEncoder.encode(request.getPassword()));
        user.setFullName(request.getFullName());
        user.setPhone(request.getPhone());
        user.setAvatarUrl(request.getAvatarUrl());
        user.setBio(request.getBio());
        user.setRoleId(role.getId());
        user.setStatus(Optional.ofNullable(request.getStatus()).orElse("active"));
        user.setEmailVerified(Boolean.TRUE.equals(request.getEmailVerified()));
        user.setRawAppMetaData("{}");
        user.setRawUserMetaData("{}");
        user.setSignInCount(0);
        user.setEmailConfirmedAt(Boolean.TRUE.equals(request.getEmailVerified()) ? LocalDateTime.now() : null);

        user = userRepository.save(user);
        Map<UUID, List<Long>> extraPermissionMap = buildExtraPermissionMap(Collections.singletonList(user));
        Map<Long, Role> roleMap = buildRoleMap(Collections.singletonList(user));
        return toResponse(user, extraPermissionMap, roleMap);
    }

    /**
     * 更新用户信息
     */
    @Transactional
    public UserResponse updateUser(UUID id, UserUpdateRequest request) {
        User user = findActiveUser(id);

        if (request.getFullName() != null) {
            user.setFullName(request.getFullName());
        }
        if (request.getPhone() != null) {
            user.setPhone(request.getPhone());
        }
        if (request.getAvatarUrl() != null) {
            user.setAvatarUrl(request.getAvatarUrl());
        }
        if (request.getBio() != null) {
            user.setBio(request.getBio());
        }
        if (request.getRawAppMetaData() != null) {
            user.setRawAppMetaData(request.getRawAppMetaData());
        }
        if (request.getRawUserMetaData() != null) {
            user.setRawUserMetaData(request.getRawUserMetaData());
        }
        if (request.getStatus() != null) {
            validateStatus(request.getStatus());
            user.setStatus(request.getStatus());
        }
        if (request.getEmailVerified() != null) {
            user.setEmailVerified(request.getEmailVerified());
            if (Boolean.TRUE.equals(request.getEmailVerified()) && user.getEmailConfirmedAt() == null) {
                user.setEmailConfirmedAt(LocalDateTime.now());
            }
        }
        if (request.getRoleId() != null) {
            Role role = roleRepository.findById(request.getRoleId())
                    .orElseThrow(() -> new ResourceNotFoundException("角色不存在"));
            user.setRoleId(role.getId());
        }

        user = userRepository.save(user);
        Map<UUID, List<Long>> extraPermissionMap = buildExtraPermissionMap(Collections.singletonList(user));
        Map<Long, Role> roleMap = buildRoleMap(Collections.singletonList(user));
        return toResponse(user, extraPermissionMap, roleMap);
    }

    /**
     * 重置密码
     */
    @Transactional
    public void resetPassword(UUID id, ResetPasswordRequest request) {
        User user = findActiveUser(id);
        user.setEncryptedPassword(passwordEncoder.encode(request.getNewPassword()));
        user.setResetToken(null);
        user.setResetTokenExpiresAt(null);
        userRepository.save(user);
    }

    /**
     * 更新用户状态
     */
    @Transactional
    public UserResponse updateStatus(UUID id, UpdateUserStatusRequest request) {
        validateStatus(request.getStatus());
        User user = findActiveUser(id);
        user.setStatus(request.getStatus());
        if ("active".equals(request.getStatus())) {
            user.setDeletedAt(null);
        }
        if ("banned".equals(request.getStatus())) {
            user.setDeletedAt(null);
        }
        user = userRepository.save(user);
        Map<UUID, List<Long>> extraPermissionMap = buildExtraPermissionMap(Collections.singletonList(user));
        Map<Long, Role> roleMap = buildRoleMap(Collections.singletonList(user));
        return toResponse(user, extraPermissionMap, roleMap);
    }

    /**
     * 分配角色
     */
    @Transactional
    public UserResponse assignRole(UUID id, AssignUserRoleRequest request) {
        User user = findActiveUser(id);
        Role role = roleRepository.findById(request.getRoleId())
                .orElseThrow(() -> new ResourceNotFoundException("角色不存在"));
        user.setRoleId(role.getId());
        user = userRepository.save(user);
        Map<UUID, List<Long>> extraPermissionMap = buildExtraPermissionMap(Collections.singletonList(user));
        Map<Long, Role> roleMap = buildRoleMap(Collections.singletonList(user));
        return toResponse(user, extraPermissionMap, roleMap);
    }

    /**
     * 软删除用户
     */
    @Transactional
    public void softDelete(UUID id) {
        User user = userRepository.findById(id)
                .orElseThrow(() -> new ResourceNotFoundException("用户不存在"));
        user.setDeletedAt(LocalDateTime.now());
        user.setStatus("inactive");
        userRepository.save(user);
    }

    // ==================== 私有工具 ====================

    private Specification<User> buildSpecification(UserQueryRequest request) {
        return (root, query, cb) -> {
            List<Predicate> predicates = new ArrayList<>();

            if (!Boolean.TRUE.equals(request.getIncludeDeleted())) {
                predicates.add(cb.isNull(root.get("deletedAt")));
            }

            if (request.getKeyword() != null && !request.getKeyword().isEmpty()) {
                String keyword = "%" + request.getKeyword().toLowerCase(Locale.ROOT) + "%";
                Predicate usernamePredicate = cb.like(cb.lower(root.get("username")), keyword);
                Predicate emailPredicate = cb.like(cb.lower(root.get("email")), keyword);
                Predicate namePredicate = cb.like(cb.lower(root.get("fullName")), keyword);
                predicates.add(cb.or(usernamePredicate, emailPredicate, namePredicate));
            }

            if (request.getStatus() != null && !request.getStatus().isEmpty()) {
                predicates.add(cb.equal(root.get("status"), request.getStatus()));
            }

            if (request.getEmailVerified() != null) {
                predicates.add(cb.equal(root.get("emailVerified"), request.getEmailVerified()));
            }

            if (request.getRoleId() != null) {
                predicates.add(cb.equal(root.get("roleId"), request.getRoleId()));
            }

            if (request.getCreatedAtStart() != null) {
                predicates.add(cb.greaterThanOrEqualTo(root.get("createdAt"), request.getCreatedAtStart()));
            }

            if (request.getCreatedAtEnd() != null) {
                predicates.add(cb.lessThanOrEqualTo(root.get("createdAt"), request.getCreatedAtEnd()));
            }

            return cb.and(predicates.toArray(new Predicate[0]));
        };
    }

    private Pageable buildPageable(Integer page, Integer pageSize, String sortBy, String sortOrder) {
        int p = Math.max(0, page - 1);
        int size = Math.min(Math.max(pageSize, 1), 200);

        String sortProperty = mapSortProperty(sortBy);
        Sort.Direction direction = "asc".equalsIgnoreCase(sortOrder) ? Sort.Direction.ASC : Sort.Direction.DESC;
        Sort sort = Sort.by(direction, sortProperty);
        if (!"createdAt".equals(sortProperty)) {
            sort = sort.and(Sort.by(Sort.Direction.DESC, "createdAt"));
        }
        return PageRequest.of(p, size, sort);
    }

    private String mapSortProperty(String sortBy) {
        if ("updatedAt".equalsIgnoreCase(sortBy)) {
            return "updatedAt";
        }
        if ("lastSignInAt".equalsIgnoreCase(sortBy)) {
            return "lastSignInAt";
        }
        if ("signInCount".equalsIgnoreCase(sortBy)) {
            return "signInCount";
        }
        return "createdAt";
    }

    private User findActiveUser(UUID id) {
        User user = userRepository.findById(id)
                .orElseThrow(() -> new ResourceNotFoundException("用户不存在"));
        if (user.getDeletedAt() != null) {
            throw new ResourceNotFoundException("用户已被删除");
        }
        return user;
    }

    private void validateStatus(String status) {
        if (status != null && !ALLOWED_STATUS.contains(status)) {
            throw new IllegalArgumentException("非法的用户状态：" + status);
        }
    }

    private UserResponse toResponse(User user,
                                    Map<UUID, List<Long>> extraPermissionMap,
                                    Map<Long, Role> roleMap) {
        List<Long> extraPermissionIds = extraPermissionMap.getOrDefault(user.getId(), Collections.emptyList());

        Role role = null;
        if (user.getRoleId() != null) {
            role = roleMap.get(user.getRoleId());
        }

        UserResponse.RoleSummary roleSummary = null;
        if (role != null) {
            roleSummary = UserResponse.RoleSummary.builder()
                    .id(role.getId())
                    .name(role.getName())
                    .displayName(role.getDisplayName())
                    .build();
        }

        return UserResponse.builder()
                .id(user.getId())
                .email(user.getEmail())
                .username(user.getUsername())
                .fullName(user.getFullName())
                .phone(user.getPhone())
                .avatarUrl(user.getAvatarUrl())
                .bio(user.getBio())
                .status(Optional.ofNullable(user.getStatus()).orElse("inactive"))
                .emailVerified(Boolean.TRUE.equals(user.getEmailVerified()))
                .emailConfirmedAt(user.getEmailConfirmedAt())
                .lastSignInAt(user.getLastSignInAt())
                .lastSignInIp(user.getLastSignInIp())
                .signInCount(Optional.ofNullable(user.getSignInCount()).orElse(0))
                .createdAt(user.getCreatedAt())
                .updatedAt(user.getUpdatedAt())
                .deletedAt(user.getDeletedAt())
                .role(roleSummary)
                .extraPermissionIds(extraPermissionIds)
                .rawAppMetaData(Optional.ofNullable(user.getRawAppMetaData()).orElse("{}"))
                .rawUserMetaData(Optional.ofNullable(user.getRawUserMetaData()).orElse("{}"))
                .build();
    }

    private Map<UUID, List<Long>> buildExtraPermissionMap(List<User> users) {
        if (users == null || users.isEmpty()) {
            return Collections.emptyMap();
        }
        List<UUID> userIds = users.stream()
                .map(User::getId)
                .collect(Collectors.toList());
        List<UserPermission> permissions = userPermissionRepository.findByIdUserIdIn(userIds);
        Map<UUID, List<Long>> map = new HashMap<>();
        for (UserPermission permission : permissions) {
            map.computeIfAbsent(permission.getId().getUserId(), key -> new ArrayList<>())
                    .add(permission.getId().getPermissionId());
        }
        return map;
    }

    private Map<Long, Role> buildRoleMap(List<User> users) {
        if (users == null || users.isEmpty()) {
            return Collections.emptyMap();
        }
        List<Long> roleIds = users.stream()
                .map(User::getRoleId)
                .filter(Objects::nonNull)
                .distinct()
                .collect(Collectors.toList());
        if (roleIds.isEmpty()) {
            return Collections.emptyMap();
        }
        List<Role> roles = roleRepository.findAllById(roleIds);
        return roles.stream().collect(Collectors.toMap(Role::getId, role -> role));
    }
}


